package com.phiture.erp.produce.core.service.impl;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.phiture.erp.basic.api.pojo.resp.ErpMaterialResp;
import com.phiture.erp.basic.api.service.ErpMaterialApi;
import com.phiture.erp.common.constants.ErpNoPrefixConstants;
import com.phiture.erp.common.enums.ErpMrpSelectedEnum;
import com.phiture.erp.common.utils.ErpNoGenerator;
import com.phiture.erp.produce.core.pojo.vo.ErpProduceMainPlanPageReqVO;
import com.phiture.erp.produce.core.pojo.vo.ErpProduceMainPlanSaveReqVO;
import com.phiture.erp.produce.core.service.ErpProduceMainPlanService;
import com.phiture.erp.produce.dal.entity.ErpProduceMainPlanDO;
import com.phiture.erp.produce.dal.mapper.ErpProduceMainPlanMapper;
import com.phiture.erp.sale.api.pojo.resp.ErpSaleOrderItemResp;
import com.phiture.erp.sale.api.pojo.resp.ErpSaleOrderResp;
import com.phiture.erp.sale.api.service.ErpSaleApi;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.phiture.erp.common.constants.ErrorCodeConstants.MAIN_PLAN_NOT_EXISTS;
import static com.phiture.erp.common.constants.ErrorCodeConstants.MAIN_PLAN_NO_EXISTS;

/**
 * 主计划 Service 实现类
 *
 * @author lekaihuai
 */
@Service
@Validated
public class ErpMainPlanServiceImpl implements ErpProduceMainPlanService {

    @Resource
    private ErpProduceMainPlanMapper mainPlanMapper;

    @Resource
    private ErpNoGenerator erpNoGenerator;

    @Resource
    private ErpSaleApi erpSaleApi;

    @Resource
    private ErpMaterialApi erpMaterialApi;

    @Override
    public Long createMainPlan(ErpProduceMainPlanSaveReqVO createReqVO) {
        // 自动生成 BOM 编号
        String mpNo = erpNoGenerator.generate(ErpNoPrefixConstants.MAIN_PLAN_NO_PREFIX);
        validateMpNo(mpNo);
        createReqVO.setNo(mpNo);
        // 插入
        ErpProduceMainPlanDO mainPlan = BeanUtils.toBean(createReqVO, ErpProduceMainPlanDO.class);
        mainPlanMapper.insert(mainPlan);
        // 返回
        return mainPlan.getId();
    }

    private void validateMpNo(String mpNo){
        boolean exists = mainPlanMapper.exists(
                Wrappers.lambdaQuery(ErpProduceMainPlanDO.class)
                        .eq(ErpProduceMainPlanDO::getNo, mpNo)
                        .eq(ErpProduceMainPlanDO::getDeleted, Boolean.FALSE)
        );
        if(exists){
            throw exception(MAIN_PLAN_NO_EXISTS);
        }
    }

    @Override
    public void updateMainPlan(ErpProduceMainPlanSaveReqVO updateReqVO) {
        // 校验存在
        validateMainPlanExists(updateReqVO.getId());
        // 更新
        ErpProduceMainPlanDO updateObj = BeanUtils.toBean(updateReqVO, ErpProduceMainPlanDO.class);
        mainPlanMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMainPlan(Long id) {
        // 校验存在
        ErpProduceMainPlanDO result = validateMainPlanExists(id);
        // 删除
        mainPlanMapper.deleteById(id);
        // 如果是自动生成的主计划，更新销售订单的MRP标志
        if (result.getSourceBillId() != null && result.getSourceBillId() > 0) {
            ErpSaleOrderResp saleOrder = erpSaleApi.getSaleOrderById(result.getSourceBillId());
            if (saleOrder != null) {
                saleOrder.setMrpFlag(ErpMrpSelectedEnum.NO.getStatus());
                erpSaleApi.updateSaleOrderMrpFlag(saleOrder.getId(), saleOrder.getMrpFlag());
            }

            // 同时更新销售订单项的MRP标志
            if (result.getSourceDetailId()!= null && result.getSourceDetailId() > 0) {
                ErpSaleOrderItemResp saleOrderItem = erpSaleApi.getSaleOrderItemById(result.getSourceDetailId());
                if (saleOrderItem!= null) {
                    saleOrderItem.setMrpFlag(ErpMrpSelectedEnum.NO.getStatus());
                    erpSaleApi.updateSaleOrderItemMrpFlag(saleOrderItem.getId(), saleOrderItem.getMrpFlag());
                }
            }
        }
    }

    private ErpProduceMainPlanDO validateMainPlanExists(Long id) {
        ErpProduceMainPlanDO mainPlan = mainPlanMapper.selectById(id);
        if (mainPlan == null) {
            throw exception(MAIN_PLAN_NOT_EXISTS);
        }
        return mainPlan;
    }

    @Override
    public ErpProduceMainPlanDO getMainPlan(Long id) {
        return mainPlanMapper.selectById(id);
    }

    @Override
    public PageResult<ErpProduceMainPlanDO> getMainPlanPage(ErpProduceMainPlanPageReqVO reqVO) {
        return mainPlanMapper.selectPage(reqVO, new LambdaQueryWrapperX<ErpProduceMainPlanDO>()
                .likeIfPresent(ErpProduceMainPlanDO::getNo, reqVO.getNo())
                .likeIfPresent(ErpProduceMainPlanDO::getSourceBillNo, reqVO.getSourceBillNo())
//                .likeIfPresent(ErpMainPlanDO::getMaterialId, reqVO.getMaterialId())
                .eqIfPresent(ErpProduceMainPlanDO::getMode, reqVO.getMode())
                .eqIfPresent(ErpProduceMainPlanDO::getRemark, reqVO.getRemark())
                .betweenIfPresent(ErpProduceMainPlanDO::getStartDate, reqVO.getStartDate())
                .betweenIfPresent(ErpProduceMainPlanDO::getEndDate, reqVO.getEndDate())
                .eqIfPresent(ErpProduceMainPlanDO::getMaterialAttr, reqVO.getMaterialAttr())
                .eqIfPresent(ErpProduceMainPlanDO::getMrpSelected, reqVO.getMrpSelected())
                .orderByDesc(ErpProduceMainPlanDO::getId));
    }

    @Override
    public void autoGenerateMainPlan(List<Long> ids) {
        // 如果物料计划信息为空，生产周期默认为7天
        Integer produceCycle = 7;
        Integer materialAttr = null;

        // 调用销售订单API，获取销售订单信息
        for (Long id : ids) {
            List<ErpSaleOrderItemResp> items = erpSaleApi.getSaleOrderItemsByOrderId(id);
            // 遍历销售订单信息，生成主计划
            for (ErpSaleOrderItemResp item : items) {

                // 如果销售订单项的MRP标志为1，则跳过
                if (item.getMrpFlag()!= null && item.getMrpFlag().equals(ErpMrpSelectedEnum.YES.getStatus())) {
                    continue;
                }

                // 根据物料ID查询物料计划信息
                List<Long> materialIds = new ArrayList<>();
                materialIds.add(item.getMaterialId());
                ErpMaterialResp material = erpMaterialApi.getMaterial(item.getMaterialId());
                if (Objects.nonNull(material)) {
                    materialAttr = material.getPlanInfo() != null ? material.getPlanInfo().getMaterialAttr() : null;
                    produceCycle = material.getPlanInfo() != null ? material.getPlanInfo().getProduceLeadTime() : 7;
                }
                // 生成主计划
                ErpProduceMainPlanSaveReqVO mainPlan = new ErpProduceMainPlanSaveReqVO();
                // 获取销售订单编号
                ErpSaleOrderResp saleOrder =  erpSaleApi.getSaleOrderById(item.getOrderId());
                mainPlan.setSourceBillNo(saleOrder.getNo());
                mainPlan.setSourceBillId(item.getOrderId());
                mainPlan.setSourceDetailId(item.getId());
                mainPlan.setRemark(item.getRemark());
                mainPlan.setUnitId(item.getMaterialUnitId());
                mainPlan.setMode(material.getStandard());
                mainPlan.setMaterialAttr(materialAttr);
                mainPlan.setMaterialId(item.getMaterialId());
                mainPlan.setQty(item.getCount());
                // 需要将交货日期提前一天设置为结束日期
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(item.getDeliveryDate());
                calendar.add(Calendar.DATE, -1);
                Date endDate = calendar.getTime();
                // 设置结束日期
                mainPlan.setEndDate(endDate);
                // 开始日期为结束日期减去生产周期
                calendar.add(Calendar.DATE, -produceCycle);
                Date startDate = calendar.getTime();
                // 设置开始日期
                mainPlan.setStartDate(startDate);
                mainPlan.setMrpSelected(ErpMrpSelectedEnum.NO.getStatus());
                mainPlan.setStatus(ErpMrpSelectedEnum.NO.getStatus());

                createMainPlan(mainPlan);
                // 更新销售订单状态
                saleOrder.setMrpFlag(ErpMrpSelectedEnum.YES.getStatus());
                erpSaleApi.updateSaleOrderMrpFlag(saleOrder.getId(), saleOrder.getMrpFlag());

                // 更新销售订单项状态
                item.setMrpFlag(ErpMrpSelectedEnum.YES.getStatus());
                erpSaleApi.updateSaleOrderItemMrpFlag(item.getId(), item.getMrpFlag());

                }
            }
    }

    @Override
    public List<ErpProduceMainPlanDO> getListByNos(Collection<String> produceMainPlanNos) {
        return mainPlanMapper.selectList(ErpProduceMainPlanDO::getNo, produceMainPlanNos);
    }

    @Override
    public void backfillMrpSelected(Collection<String> produceMainPlanNos) {
        mainPlanMapper.update(
                Wrappers.lambdaUpdate(ErpProduceMainPlanDO.class)
                        .set(ErpProduceMainPlanDO::getMrpSelected, ErpMrpSelectedEnum.YES.getStatus())
                        .in(ErpProduceMainPlanDO::getNo, produceMainPlanNos)
                        .eq(ErpProduceMainPlanDO::getDeleted, Boolean.FALSE)
        );
    }

    @Override
    public Map<String, String> getMainPlanNoSaleOrderNoMapByMainPlanNos(Collection<String> produceMainPlanNos) {
        List<ErpProduceMainPlanDO> mainPlanList = mainPlanMapper.selectList(
                Wrappers.lambdaQuery(ErpProduceMainPlanDO.class)
                        .select(ErpProduceMainPlanDO::getNo, ErpProduceMainPlanDO::getSourceBillNo)
                        .in(ErpProduceMainPlanDO::getNo, produceMainPlanNos)
                        .eq(ErpProduceMainPlanDO::getDeleted, Boolean.FALSE)
        );
        Map<String, String> mainPlanNoSaleOrderNoMap = new HashMap<>();
        for (ErpProduceMainPlanDO mainPlan : mainPlanList) {
            mainPlanNoSaleOrderNoMap.put(mainPlan.getNo(), mainPlan.getSourceBillNo());
        }
        return mainPlanNoSaleOrderNoMap;
    }

}